﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;

namespace Xpus.Website.Utilities
{
	/// <summary>
	/// 能够与字符串进行相互转换的接口。
	/// </summary>
	public interface IStringConvertible
	{
		/// <summary>
		/// 从字符串构造实现了<see cref="IStringConvertible"/>接口的对象。
		/// </summary>
		/// <param name="value">包含对象值的字符串。</param>
		void ConvertFromString(string value);

		/// <summary>
		/// 将对象转换成字符串。
		/// </summary>
		/// <returns>包含给定值的对象。</returns>
		string ConvertToString();
	}

	/// <summary>
	/// 表示存放在字符串中的一系列设置。
	/// </summary>
	public sealed class SettingsUtility
	{
		/// <summary>
		/// 设置与设置之间的分隔符字符。
		/// </summary>
		public static readonly string SettingsSeparator = char.ConvertFromUtf32(0x0000000C);  // NP (New Page), FF (Form Feed)

		/// <summary>
		/// 对于每一个设置，其键与值之间的分隔符。
		/// </summary>
		public static readonly string KeyValueSeparator = char.ConvertFromUtf32(0x0000001C);  // FS (File Separator)

		Dictionary<string, string> _settings = new Dictionary<string, string>();

		/// <summary>
		/// 使用包含设置信息的字符串构造<see cref="SettingsUtility"/>对象。
		/// </summary>
		public SettingsUtility(string settingsString)
		{
			string[] items = settingsString.Split(new string[] { SettingsSeparator }, StringSplitOptions.RemoveEmptyEntries);
			foreach(string s in items)
			{
				string[] pair = s.Split(new string[] { KeyValueSeparator }, StringSplitOptions.RemoveEmptyEntries);
				if(pair.Length != 2)
					throw new FormatException(LanguageUtility.GetString("Settings string's format is invalid."));

				_settings.Add(pair[0], pair[1]);
			}
		}

		/// <summary>
		/// 已重写。将<see cref="SettingsUtility"/>对象转换为字符串。
		/// </summary>
		/// <returns>包含配置信息的字符串。</returns>
		public override string ToString()
		{
			StringBuilder sbSettings = new StringBuilder();

			foreach (string key in _settings.Keys)
			{
				sbSettings.Append(key);
				sbSettings.Append(KeyValueSeparator);
				sbSettings.Append(_settings[key]);
				sbSettings.Append(SettingsSeparator);
			}

			return sbSettings.ToString();
		}

		/// <summary>
		/// 从设置中删除一个设置入口。
		/// </summary>
		/// <param name="key">要删除的设置的键。</param>
		/// <returns>如果设置中存在对应的key，则删除之，并返回true；否则返回false。</returns>
		public bool RemoveEntry(string key)
		{
			bool hasKey = _settings.ContainsKey(key);

			if (hasKey)
				_settings.Remove(key);

			return hasKey;
		}

		#region Set方法
		/// <summary>
		/// 向设置中添加一个<see cref="sbyte"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, sbyte value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="byte"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, byte value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="short"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, short value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="ushort"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, ushort value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="int"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, int value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="uint"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, uint value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="long"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, long value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="ulong"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, ulong value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="float"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, float value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="double"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, double value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="decimal"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, decimal value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="bool"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, bool value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="char"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, char value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ToString();
			else
				_settings.Add(key, value.ToString());
		}

		/// <summary>
		/// 向设置中添加一个<see cref="string"/>值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set(string key, string value)
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value;
			else
				_settings.Add(key, value);
		}

		/// <summary>
		/// 向设置中添加一个实现了<see cref="IStringConvertible"/>接口的值。
		/// </summary>
		/// <param name="key">键。</param>
		/// <param name="value">值。</param>
		public void Set<T>(string key, T value) where T : IStringConvertible
		{
			if (_settings.ContainsKey(key))
				_settings[key] = value.ConvertToString();
			else
				_settings.Add(key, value.ConvertToString());
		}
		#endregion

		#region Get方法
		/// <summary>
		/// 从设置中获取一个<see cref="sbyte"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="sbyte"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public sbyte Get(string key, sbyte defaultValue)
		{
			sbyte retval;

			if (_settings.ContainsKey(key) && sbyte.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="byte"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="byte"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public byte Get(string key, byte defaultValue)
		{
			byte retval;

			if (_settings.ContainsKey(key) && byte.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="short"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="short"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public short Get(string key, short defaultValue)
		{
			short retval;

			if (_settings.ContainsKey(key) && short.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="ushort"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="ushort"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public ushort Get(string key, ushort defaultValue)
		{
			ushort retval;

			if (_settings.ContainsKey(key) && ushort.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="int"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="int"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public int Get(string key, int defaultValue)
		{
			int retval;

			if (_settings.ContainsKey(key) && int.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="uint"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="uint"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public uint Get(string key, uint defaultValue)
		{
			uint retval;

			if (_settings.ContainsKey(key) && uint.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="long"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="long"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public long Get(string key, long defaultValue)
		{
			long retval;

			if (_settings.ContainsKey(key) && long.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="ulong"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="ulong"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public ulong Get(string key, ulong defaultValue)
		{
			ulong retval;

			if (_settings.ContainsKey(key) && ulong.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="float"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="float"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public float Get(string key, float defaultValue)
		{
			float retval;

			if (_settings.ContainsKey(key) && float.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="double"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="double"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public double Get(string key, double defaultValue)
		{
			double retval;

			if (_settings.ContainsKey(key) && double.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="decimal"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="decimal"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public decimal Get(string key, decimal defaultValue)
		{
			decimal retval;

			if (_settings.ContainsKey(key) && decimal.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="bool"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="bool"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public bool Get(string key, bool defaultValue)
		{
			bool retval;

			if (_settings.ContainsKey(key) && bool.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="char"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="char"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public char Get(string key, char defaultValue)
		{
			char retval;

			if (_settings.ContainsKey(key) && char.TryParse(_settings[key], out retval))
				return retval;
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个<see cref="string"/>值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="string"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public string Get(string key, string defaultValue)
		{
			if (_settings.ContainsKey(key))
				return _settings[key];
			else
				return defaultValue;
		}

		/// <summary>
		/// 从设置中获取一个实现了<see cref="IStringConvertible"/>接口的值。
		/// </summary>
		/// <param name="key">键</param>
		/// <param name="defaultValue">默认值。</param>
		/// <returns>如果设置中存在<see cref="key"/>所指定的键，并且其值能够转换为<see cref="IStringConvertible"/>类型，则返回对应的设置值；否则返回<see cref="defaultValue"/>所指定的默认值。</returns>
		public T Get<T>(string key, T defaultValue) where T : IStringConvertible, new()
		{
			if (_settings.ContainsKey(key))
			{
				try
				{
					T retval = new T();
					retval.ConvertFromString(_settings[key]);
					return retval;
				}
				catch
				{
				}
			}

			return defaultValue;
		}
		#endregion
	}
}
